package storage.file;

import config.Config;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

import represent.type.*;

public class Block {


	/**
	 * header contains (in byte):
	 * 0-3		: fileID
	 * 4-7		: block_number
	 * 8-11		: pointer to the next block
	 * 12-15	: pointer to the previous block
	 */
	//	private static final int blockSize = Config.getInteger("blockSize", 4096);	// 4KB
	private static final int BLOCK_HEADER_LENGTH = 4;
//	private byte[] header = new byte[BLOCK_HEADER_LENGTH];
//	private byte[] content = new byte[BLOCK_SIZE - BLOCK_HEADER_LENGTH];


	//---------------------------------------------------
	public static final int BLOCK_SIZE =Config.getInteger("blockSize",4096);
	public static final int INT_SIZE = Integer.SIZE / Byte.SIZE;
	public static final int BYTE_SIZE = 1;
	public static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
	public static final int DOUBLE_SIZE = Double.SIZE / Byte.SIZE;
	public static final int LONG_SIZE = Long.SIZE / Byte.SIZE;
	public static final int BOOLEAN_SIZE = 1;
	//----------------------------------------------------


	public static final int STRING_SIZE(int n) {
		float bytesPerChar = Charset.defaultCharset().newEncoder().maxBytesPerChar();
		return INT_SIZE + (n * (int) bytesPerChar);
	}

	private ByteBuffer contents = ByteBuffer.allocateDirect(BLOCK_SIZE);
	private AbstractFileManager fileManager = FileManagerFactory.getFileManager();

	public Block() {
	}

	public synchronized void read(BlockID blockID) {
		fileManager.read(blockID, contents);
	}
	public synchronized void write(BlockID blockID) {
		fileManager.write(blockID, contents);
	}
	public synchronized BlockID append(String fileName) {
		return fileManager.append(fileName, contents);
	}
	public synchronized long getLong(int offset) {
		contents.position(offset);
		return contents.getLong();
	}
	public synchronized void setLong(int offset, long val) {
		contents.position(offset);
		contents.putLong(val);
	}
	public synchronized boolean getBoolean(int offset) {
		contents.position(offset);
		byte T = 1;
		if ((new Byte(contents.get())).equals(T))return true;
		else return false;
	}
	public synchronized void setBoolean(int offset, boolean Val) {
		contents.position(offset);
		byte T = 1;
		byte F = -1;
		if (Val) {contents.put(T);} 
		else {contents.put(F);}
	}
	public synchronized byte getByte(int offset) {
		contents.position(offset);
		return contents.get();
	}
	public synchronized void SetByte(int offset, byte input) {
		contents.position(offset);
		contents.put(input);
	}
	public synchronized int getInt(int offset) {
		contents.position(offset);
		return contents.getInt();
	}
	public synchronized void setInt(int offset, int val) {
		contents.position(offset);
		contents.putInt(val);
	}
	public synchronized String getString(int offset) {
		contents.position(offset);
		int len = contents.getInt();
		//TODO
		//Read the file"String",len is the offset
		//
		return null;
	}
	public synchronized void setString(int offset, String val) {
		contents.position(offset);
		byte[] byteval = val.getBytes();
        //TODO
	}
	public synchronized double getDouble(int offset) {
		contents.position(offset);
		return contents.getDouble();
	}
	public synchronized void setDouble(int offset, double a) {
		contents.position(offset);
		contents.putDouble(a);
	}
	
	public synchronized float getFloat(int offset) {
		contents.position(offset);
		return contents.getFloat();
	}
	public synchronized void setFloat(int offset, float b) {
		contents.position(offset);
		contents.putFloat(b);
	}
	public void setVal(int offset, Type val) {

		if (val instanceof IntType)
			setInt(offset, (Integer) val.asJavaVal());
		else if (val instanceof BoolType)
			setBoolean(offset, (Boolean) val.asJavaVal());
		else if (val instanceof FloatType)
			setFloat(offset, (Float) val.asJavaVal());
		else if (val instanceof DateType)
			setString(offset, (String) val.asJavaVal());
		else if (val instanceof StringType)
			setString(offset, (String) val.asJavaVal());
		else if (val instanceof DecimalType)
			setDouble(offset, (Double) val.asJavaVal());
		else if (val instanceof TimeStampType)
			setString(offset, (String) val.asJavaVal());
	}
}
